import { Injectable, Logger } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { promises as fs } from 'fs';
import * as path from 'path';
import { ILanguageService } from './language.interface';

/**
 * 语言服务
 * 基于 NestJS 实现模块化多语言支持
 * 符合NestJS规范的服务层实现
 * 对应PHP: think\Lang 类
 * 对应Java: MessageSource 实现
 */
@Injectable()
export class LanguageService implements ILanguageService {
  private readonly logger = new Logger(LanguageService.name);
  private readonly languageCache = new Map<string, Map<string, any>>();
  private readonly moduleCache = new Map<string, Set<string>>(); // 记录已加载的模块

  constructor(private readonly configService: ConfigService) {
    this.initializeLanguagePacks();
  }

  /**
   * 获取消息
   * @param key 消息键
   * @param args 参数
   * @param module 模块名
   * @param type 类型 (api|dict|validate)
   * @param language 语言
   * @returns 消息内容
   */
  async getMessage(key: string, args?: any, module: string = 'common', type: string = 'api', language?: string): Promise<string> {
    try {
      const currentLanguage = language || this.getCurrentLanguage();
      const cacheKey = `${type}.${module}.${key}`;
      
      // 确保模块已加载
      await this.ensureModuleLoaded(module, type, currentLanguage);
      
      const message = this.getMessageFromCache(cacheKey, currentLanguage);
      
      if (message && message !== key) {
        // 支持参数替换
        if (args && typeof args === 'object') {
          return this.replaceMessageParams(message, args);
        }
        return message;
      }
      
      this.logger.warn(`未找到消息: ${key} (模块: ${module}, 类型: ${type}, 语言: ${currentLanguage})`);
      return key;
    } catch (error) {
      this.logger.warn(`获取消息失败: ${key}`, error);
      return key;
    }
  }

  /**
   * 获取消息（实例方法）
   * @param key 消息键
   * @param args 参数
   * @param module 模块名
   * @param type 类型
   * @param language 语言
   * @returns 消息内容
   */
  async get(key: string, args?: any, module: string = 'common', type: string = 'api', language?: string): Promise<string> {
    return await this.getMessage(key, args, module, type, language);
  }

  /**
   * 初始化语言包
   * 只加载通用语言包，其他模块按需加载
   */
  private async initializeLanguagePacks(): Promise<void> {
    try {
      const supportedLanguages = this.getSupportedLanguages();
      for (const language of supportedLanguages) {
        // 只加载通用模块
        await this.loadModuleLanguagePack('common', 'api', language);
        await this.loadModuleLanguagePack('common', 'dict', language);
        await this.loadModuleLanguagePack('common', 'validate', language);
      }
      this.logger.log('通用语言包初始化完成');
    } catch (error) {
      this.logger.error('语言包初始化失败', error);
    }
  }

  /**
   * 确保模块已加载
   * @param module 模块名
   * @param type 类型
   * @param language 语言
   */
  private async ensureModuleLoaded(module: string, type: string, language: string): Promise<void> {
    const moduleKey = `${module}.${type}`;
    const languageKey = `${language}.${moduleKey}`;
    
    if (!this.moduleCache.has(language) || !this.moduleCache.get(language)!.has(moduleKey)) {
      await this.loadModuleLanguagePack(module, type, language);
    }
  }

  /**
   * 加载模块语言包
   * @param module 模块名
   * @param type 类型 (api|dict|validate)
   * @param language 语言
   */
  private async loadModuleLanguagePack(module: string, type: string, language: string): Promise<void> {
    try {
      const langDir = path.join(process.cwd(), 'src', 'lang', language);
      const languagePack = new Map<string, any>();
      
      // 1. 加载通用语言包
      if (module !== 'common') {
        await this.loadCommonLanguagePack(langDir, type, languagePack);
      }
      
      // 2. 加载模块语言包
      await this.loadModuleSpecificPack(langDir, module, type, languagePack);
      
      // 3. 加载插件语言包
      await this.loadAddonLanguagePacks(langDir, type, languagePack);
      
      // 4. 缓存语言包
      if (!this.languageCache.has(language)) {
        this.languageCache.set(language, new Map());
      }
      
      const languageCache = this.languageCache.get(language)!;
      for (const [key, value] of languagePack) {
        languageCache.set(key, value);
      }
      
      // 5. 记录已加载的模块
      if (!this.moduleCache.has(language)) {
        this.moduleCache.set(language, new Set());
      }
      this.moduleCache.get(language)!.add(`${module}.${type}`);
      
      this.logger.log(`模块语言包加载完成: ${module}.${type} (${language})`);
    } catch (error) {
      this.logger.error(`加载模块语言包失败: ${module}.${type} (${language})`, error);
    }
  }

  /**
   * 加载通用语言包
   */
  private async loadCommonLanguagePack(langDir: string, type: string, languagePack: Map<string, any>): Promise<void> {
    const commonDir = path.join(langDir, 'common');
    const filePath = path.join(commonDir, `${type}.json`);
    
    try {
      const content = await fs.readFile(filePath, 'utf8');
      const data = JSON.parse(content);
      
      // 合并到语言包，添加前缀
      for (const [key, value] of Object.entries(data)) {
        languagePack.set(`${type}.common.${key}`, value);
      }
    } catch (error) {
      this.logger.warn(`加载通用语言包失败: ${type}`, error);
    }
  }

  /**
   * 加载模块特定语言包
   */
  private async loadModuleSpecificPack(langDir: string, module: string, type: string, languagePack: Map<string, any>): Promise<void> {
    const moduleDir = path.join(langDir, module);
    const filePath = path.join(moduleDir, `${type}.json`);
    
    try {
      const content = await fs.readFile(filePath, 'utf8');
      const data = JSON.parse(content);
      
      // 合并到语言包，添加前缀
      for (const [key, value] of Object.entries(data)) {
        languagePack.set(`${type}.${module}.${key}`, value);
      }
    } catch (error) {
      this.logger.warn(`加载模块语言包失败: ${module}.${type}`, error);
    }
  }

  /**
   * 加载插件语言包
   */
  private async loadAddonLanguagePacks(langDir: string, type: string, languagePack: Map<string, any>): Promise<void> {
    const addonsDir = path.join(langDir, 'addons');
    
    try {
      const addonDirs = await fs.readdir(addonsDir);
      for (const addonDir of addonDirs) {
        const addonPath = path.join(addonsDir, addonDir);
        const stat = await fs.stat(addonPath);
        
        if (stat.isDirectory()) {
          const filePath = path.join(addonPath, `${type}.json`);
          try {
            const content = await fs.readFile(filePath, 'utf8');
            const data = JSON.parse(content);
            
            // 合并到语言包，添加前缀
            for (const [key, value] of Object.entries(data)) {
              languagePack.set(`${type}.addon.${addonDir}.${key}`, value);
            }
          } catch (error) {
            this.logger.warn(`加载插件语言包失败: ${addonDir}.${type}`, error);
          }
        }
      }
    } catch (error) {
      this.logger.warn(`扫描插件语言包失败: ${type}`, error);
    }
  }

  /**
   * 合并语言数据
   */
  private mergeLanguageData(target: Map<string, any>, source: Record<string, any>): void {
    for (const [key, value] of Object.entries(source)) {
      target.set(key, value);
    }
  }

  /**
   * 从缓存获取消息
   */
  private getMessageFromCache(key: string, language: string): string {
    const languagePack = this.languageCache.get(language);
    if (languagePack && languagePack.has(key)) {
      return languagePack.get(key);
    }
    
    return key; // 未找到，返回key作为fallback
  }

  /**
   * 替换消息参数
   * 对应 Java: MessageFormat.format()
   */
  private replaceMessageParams(message: string, args: Record<string, any>): string {
    let result = message;
    for (const [key, value] of Object.entries(args)) {
      const placeholder = `{${key}}`;
      result = result.replace(new RegExp(placeholder, 'g'), String(value));
    }
    return result;
  }

  /**
   * 获取当前语言
   * @returns 当前语言
   */
  getCurrentLanguage(): string {
    return this.getDefaultLanguage();
  }

  /**
   * 设置语言
   * @param language 语言代码
   */
  setLanguage(language: string): void {
    this.logger.log(`设置语言: ${language}`);
  }

  /**
   * 获取支持的语言列表
   * @returns 支持的语言列表
   */
  getSupportedLanguages(): string[] {
    return this.configService.get('app.supportedLocales', ['zh_CN', 'en_US']);
  }

  /**
   * 获取默认语言
   * @returns 默认语言
   */
  getDefaultLanguage(): string {
    return this.configService.get('app.defaultLanguage', 'zh_CN');
  }

  /**
   * 检查语言是否支持
   * @param language 语言代码
   * @returns 是否支持
   */
  isLanguageSupported(language: string): boolean {
    const supportedLanguages = this.getSupportedLanguages();
    return supportedLanguages.includes(language);
  }

  /**
   * 重新加载语言包
   */
  async reloadLanguagePack(language: string): Promise<void> {
    try {
      // 清除该语言的所有缓存
      this.languageCache.delete(language);
      this.moduleCache.delete(language);
      
      // 重新加载通用语言包
      await this.loadModuleLanguagePack('common', 'api', language);
      await this.loadModuleLanguagePack('common', 'dict', language);
      await this.loadModuleLanguagePack('common', 'validate', language);
      
      this.logger.log(`重新加载语言包完成: ${language}`);
    } catch (error) {
      this.logger.error(`重新加载语言包失败: ${language}`, error);
    }
  }

  /**
   * 重新加载所有语言包
   */
  async reloadAllLanguagePacks(): Promise<void> {
    try {
      this.languageCache.clear();
      this.moduleCache.clear();
      await this.initializeLanguagePacks();
      this.logger.log('所有语言包重新加载完成');
    } catch (error) {
      this.logger.error('重新加载所有语言包失败', error);
    }
  }

  /**
   * 获取API消息
   * @param key 消息键
   * @param args 参数
   * @param module 模块名
   * @param language 语言
   */
  async getApiMessage(key: string, args?: any, module: string = 'common', language?: string): Promise<string> {
    const currentLanguage = language || this.getCurrentLanguage();
    return this.getMessage(key, args, module, 'api', currentLanguage);
  }

  /**
   * 获取字典数据
   * @param key 字典键
   * @param args 参数
   * @param module 模块名
   * @param language 语言
   */
  async getDictData(key: string, args?: any, module: string = 'common', language?: string): Promise<string> {
    const currentLanguage = language || this.getCurrentLanguage();
    return this.getMessage(key, args, module, 'dict', currentLanguage);
  }

  /**
   * 获取验证器消息
   * @param key 验证器键
   * @param args 参数
   * @param module 模块名
   * @param language 语言
   */
  async getValidateMessage(key: string, args?: any, module: string = 'common', language?: string): Promise<string> {
    const currentLanguage = language || this.getCurrentLanguage();
    return this.getMessage(key, args, module, 'validate', currentLanguage);
  }

  /**
   * 批量获取消息
   * @param keys 消息键数组
   * @param module 模块名
   * @param type 类型
   * @param language 语言
   */
  async getBatchMessages(keys: string[], module: string = 'common', type: string = 'api', language?: string): Promise<Record<string, string>> {
    const results: Record<string, string> = {};
    const currentLanguage = language || this.getCurrentLanguage();
    
    for (const key of keys) {
      results[key] = await this.getMessage(key, undefined, module, type, currentLanguage);
    }
    
    return results;
  }
}
